<?php

namespace yunj\core\validate;

use yunj\core\builder\YunjTable;
use yunj\core\constants\BuilderConst;
use yunj\core\enum\Def;
use yunj\core\Validate;
use yunj\core\builder\YunjTable as YTBuilder;

class YunjTableValidate extends Validate {

    protected $rule = [
        BuilderConst::ID_KEY => 'require',
        BuilderConst::ASYNC_TYPE_KEY => 'require|in:stateCount,count,items,event,export',
    ];

    protected $message = [
        BuilderConst::ID_KEY . '.require' => '访问错误',
        BuilderConst::ASYNC_TYPE_KEY . '.require' => '[' . BuilderConst::ASYNC_TYPE_KEY . ']参数缺失',
        BuilderConst::ASYNC_TYPE_KEY . '.in' => '[' . BuilderConst::ASYNC_TYPE_KEY . ']参数错误',
    ];

    protected $scene = [
        'AsyncRequest' => [BuilderConst::ID_KEY, BuilderConst::ASYNC_TYPE_KEY],
    ];

    /**
     * @var YunjTable
     */
    private $builder;

    /**
     * @var string
     */
    private $pksKey;

    protected function handleData(array &$data, $scene): void {
        $this->builder = $data['builder'];

        if ($scene == 'AsyncRequest') {
            $this->checkFilter($data);
            $this->checkSort($data);
            switch ($data[BuilderConst::ASYNC_TYPE_KEY]) {
                case 'stateCount':
                    $this->handleDataByStateCount($data);
                    break;
                case 'count':
                    $this->handleDataByCount($data);
                    break;
                case 'items':
                    $this->handleDataByItems($data);
                    break;
                case 'event':
                    $this->handleDataByEvent($data);
                    break;
                case 'export':
                    $this->handleDataByExport($data);
                    break;
            }
        }
    }

    private function handleDataByStateCount(&$data) {
        return $data;
    }

    private function handleDataByCount(&$data) {
        // filter补充主键集合
        $data['filter'][$this->pksKey] = [];
        return $data;
    }

    private function handleDataByItems(&$data) {
        //验证page、limit
        $data['page'] = $data['page'] ?? 1;
        $data['limit'] = $data['limit'] ?? Def::LIST_PAGE_LIMIT;
        if (!is_positive_integer($data['page']) || !is_positive_integer($data['limit'])) throw_error_json('请求参数类型异常');
        $data['pageSize'] = $data['limit'];
        // filter补充pks
        $data['filter'][$this->pksKey] = [];
        return $data;
    }

    private function handleDataByEvent(&$data) {
        if (!isset($data[BuilderConst::ASYNC_EVENT_KEY])) throw_error_json('请求参数异常');
        $data['filter'][$this->pksKey] = isset($data['filter'][$this->pksKey]) && is_array($data['filter'][$this->pksKey]) ? $data['filter'][$this->pksKey] : [];
        return $data;
    }

    private function handleDataByExport(&$data) {
        //验证 num、limit
        if (!isset($data['num'])) throw_error_json('请求参数异常');
        if (!is_positive_integer($data['num'])) throw_error_json('请求参数类型异常');
        $data['limit'] = YTBuilder::EXPORT_LIMIT;
        return $data;
    }

    private function checkFilter(&$data) {
        // 以下请求类型不检查filter
        $excludeTypeArr = ['stateCount'];
        if (in_array($data[BuilderConst::ASYNC_TYPE_KEY], $excludeTypeArr)) return $data;

        if (!isset($data["filter"])) throw_error_json('[filter]参数缺失');
        $data['filter'] = is_array($data['filter']) ? $data['filter'] : json_decode($data['filter'], true);
        $this->checkFilterState($data);
        $this->checkFilterPks($data);
        return $data;
    }

    // 校验state，并设置pksKey
    private function checkFilterState(&$data) {
        // 以下请求类型不检查filter的state参数
        $excludeTypeArr = [];
        if ($excludeTypeArr && !in_array($data[BuilderConst::ASYNC_TYPE_KEY], $excludeTypeArr) && !array_key_exists('state', $data['filter'])) {
            throw_error_json('filter请求参数[state]异常');
        }
        $this->pksKey = $this->builder->getPksKey($data['filter']['state'] ?? null);
        return $data;
    }

    private function checkFilterPks(&$data) {
        // 以下请求类型需检查filter的pks参数
        $typeArr = ['export'];
        if (!in_array($data[BuilderConst::ASYNC_TYPE_KEY], $typeArr)) return $data;
        if (!isset($data['filter'][$this->pksKey])) throw_error_json("filter请求参数[{$this->pksKey}]缺失");
        foreach ($data['filter'][$this->pksKey] as $k => $id) {
            $id = filter_sql($id);
            if (!$id === '') throw_error_json("filter请求参数[{$this->pksKey}]异常");
            $data['filter'][$this->pksKey][$k] = $id;
        }
        return $data;
    }

    private function checkSort(&$data) {
        // 以下请求类型需检查sort参数
        $typeArr = ['items', 'export'];
        if (!in_array($data[BuilderConst::ASYNC_TYPE_KEY], $typeArr)) return $data;
        if (!array_key_exists('sort', $data)) throw_error_json('[sort]参数缺失');
        $sort = is_array($data['sort']) ? $data['sort'] : json_decode($data['sort'], true);
        foreach ($sort as $k => $v) {
            if (!$this->regex($k, "alphaDash")) throw_error_json("[sort][{$k}]只能为字母/数字/下划线组合");
            if (!in_array($v, ['asc', 'desc'])) throw_error_json("[sort][{$k}]值只能为asc/desc");
        }
        $data['sort'] = $sort;
        return $sort;
    }

}